package me.zhengjie.config.aspect;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SimplePropertyPreFilter;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

@Component
public class SystemLogAspect {
    private final static Logger LOG = LoggerFactory.getLogger(SystemLogAspect.class);

    // 定义一个切点
    @Pointcut("execution(public * me.zhengjie.*.rest..*Controller.*(..))")
    public void controllerPointcut() {
    }

    @Before("controllerPointcut()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        // 开始打印请求日志
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        Signature signature = joinPoint.getSignature();
        String name = signature.getName();
        // 打印前端请求信息
        LOG.info("=== 开始 ===");
        LOG.info("请求地址: {} {}", request.getRequestURL().toString(), request.getMethod());
        LOG.info("类名方法: {}.{}", signature.getDeclaringTypeName(), name);
        LOG.info("远程地址: {}", request.getRemoteAddr());
        // 打印请求参数
        Object[] args = joinPoint.getArgs();
        Object[] arguments = new Object[args.length];
        for (int i = 0; i < args.length; i++) {
            if (args[i] instanceof ServletRequest || args[i] instanceof ServletResponse || args[i] instanceof MultipartFile) {
                continue;
            }
            arguments[i] = args[i];
        }
        // 当某些字段太敏感，或者是太长时，就不显示
        String[] excludeProperties = {"password", "file"};
        SimplePropertyPreFilter filters = new SimplePropertyPreFilter();
        for (String str : excludeProperties) {
            filters.getExcludes().add(str);
        }
        LOG.info("请求的参数: {}", JSON.toJSONString(arguments, filters));
    }

    @Around("controllerPointcut()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object result = proceedingJoinPoint.proceed();
        // 当某些字段太敏感，或者是太长时，就不显示
        String[] excludeProperties = {"password", "file"};
        SimplePropertyPreFilter filters = new SimplePropertyPreFilter();
        for (String str : excludeProperties) {
            filters.getExcludes().add(str);
        }
        LOG.info("返回的结果: {}", JSON.toJSONString(result, filters));
        LOG.info("=== 结束时，总耗时：{} ms ===", System.currentTimeMillis() - startTime);
        return result;
    }

    /*** 使用 Nginx 进行反向代理，这个方法主要是用来获取远程 IP* @param request* @return*/
    public String getRemoteIp(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}